﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DigitsRecognizer.NeuralNetwork;

namespace NeuralNetwork
{
    class Writer<T>
    {
        string final;

        public bool SavaParams(IEnumerable<T> list, double e, string login) 
        {
            if (list == null) 
            {
                return false;
            }
            ConvertParams(list, e);
            try
            {
                FileStream fs = new FileStream(string.Format("Params_{0}.txt", login), FileMode.Append, FileAccess.Write);
                StreamWriter sw = new StreamWriter(fs);
                sw.Write(final);
                sw.Close();
                return true;
            }
            catch (IOException ex) 
            {
                Console.WriteLine(ex);
                return false;
            }
        }

        private void ConvertParams(IEnumerable<T> list, double e) 
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("-- P A R A M E T R Y --");
            sb.AppendFormat("\t{0}:{1}:{2}\t{3}/{4}/{5}", DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second, DateTime.Now.Day, DateTime.Now.Month, DateTime.Now.Year);
            sb.AppendLine();
            sb.Append("{E=");
            sb.AppendFormat("{0:0.00}", e);
            sb.Append("}");
            sb.AppendLine();
            sb.AppendLine("{");
            for (int i = 0; i < list.Count(); i++) 
            {
                sb.Append(list.ElementAt(i));
                if (i == list.Count() - 1)
                {
                    sb.Append("}");
                }
                else 
                {
                    sb.Append("\t");
                }
            }
            sb.AppendLine();
            sb.AppendLine();
            sb.AppendLine();
            final = sb.ToString();
        }


        // NeuralNetwork
        public bool SavaNeuralNetworkParams(double e, int NumberOfInputs, List<List<Neuron>> HiddenLayer, List<Neuron> OutputLayer, string login, WriteReadDestination destination) 
        {
            string fileName;
            switch (destination) 
            { 
                case WriteReadDestination.OneFile:
                    fileName = string.Format("NeuralNetworkParams_{0}.txt", login);
                    break;
                
                default:
                    fileName = string.Format("NeuralNetworkParams_{0}_{1}.txt", login, e);
                    break;

            }
            ConvertNeuralNetworkParams(e, NumberOfInputs, HiddenLayer, OutputLayer);
            try
            {
                FileStream fs = new FileStream(fileName, FileMode.Append, FileAccess.Write);
                StreamWriter sw = new StreamWriter(fs);
                sw.Write(final);
                sw.Close();
                return true;
            }
            catch (IOException ex) 
            {
                Console.WriteLine(ex);
                return false;
            }
        }

        private void ConvertNeuralNetworkParams(double e, int NumberOfInputs, List<List<Neuron>> HiddenLayer, List<Neuron> OutputLayer)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("-- P A R A M E T R Y   S I E C I --");
            sb.AppendFormat("\t{0}:{1}:{2}\t{3}/{4}/{5}", DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second, DateTime.Now.Day, DateTime.Now.Month, DateTime.Now.Year);
            sb.AppendLine();
            sb.Append("{E=");
            sb.AppendFormat("{0:0.00}", e);
            sb.Append("}");
            sb.AppendLine();
            sb.Append("{IL: NumberOfInputs: ");
            sb.Append(NumberOfInputs);
            sb.Append("}");
            sb.AppendLine();
            sb.Append("{HL: NumberOfLayers: ");
            sb.Append(HiddenLayer.Count);
            sb.Append(", NeuronsInLayers: ");
            for (int i = 0; i < HiddenLayer.Count; i++)
            {
                if (i == HiddenLayer.Count - 1)
                {
                    sb.Append(HiddenLayer[i].Count);
                    sb.Append("}");
                }
                else 
                {
                    sb.Append(HiddenLayer[i].Count);
                    sb.Append("\t");
                }
            }
            sb.AppendLine();
            sb.Append("{SynapsesWeights: ");
            for (int i = 0; i < HiddenLayer.Count; i++)
            {
                for (int j = 0; j < HiddenLayer[i].Count; j++)
                {
                    for (int k = 0; k < HiddenLayer[i][j].NumberOfInputSignals; k++)
                    {
                        if (i == HiddenLayer.Count - 1 && j == HiddenLayer[i].Count - 1 && k == HiddenLayer[i][j].NumberOfInputSignals - 1)
                        {
                            sb.Append(HiddenLayer[i][j][k].SynapseWeight);
                            sb.Append("}");
                        }
                        else 
                        {
                            sb.Append(HiddenLayer[i][j][k].SynapseWeight);
                            sb.Append("\t");
                        }
                    }
                }
            }

            sb.AppendLine();
            sb.Append("{OL: NumberOfOutputs: ");
            sb.Append(OutputLayer.Count);
            sb.Append("}");
            sb.AppendLine();
            sb.Append("{Weights: ");

            for (int i = 0; i < OutputLayer.Count; i++)
            {
                for (int j = 0; j < OutputLayer[i].NumberOfInputSignals; j++)
                {
                    if (i == OutputLayer.Count - 1 && j == OutputLayer[i].NumberOfInputSignals - 1)
                    {
                        sb.Append(OutputLayer[i][j].SynapseWeight);
                        sb.Append("}");
                    }
                    else
                    {
                        sb.Append(OutputLayer[i][j].SynapseWeight);
                        sb.Append("\t");
                    }
                }
            }
            sb.AppendLine();
            sb.AppendLine();
            final = sb.ToString();
        }
    }
}
